package com.kin207.netty.config;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConstructorUtils;
import org.apache.commons.beanutils.MethodUtils;

public class CBean {
	private String name;
	private String className;
	private String initMethod;
	private Object[] initArg;
	private String scope;
	private Map<String,Object> propertys;
	private Object[] constructorArg;
	private String describe;
	private String factoryBean;
	private String factoryMethod;
	
	private Object single;
	private Class clazz;
	
	public Object get() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException{
		Object result = null;
		if(scope==null || scope.trim().equals("") || "single".equals(scope)){
			if(single==null){
				single = newObject(className);
			}
			result = single;
		}else{
			result = newObject(className);
		}
		return result;
	}
	
	private Object newObject(String className) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException{
		Object result = null;
		if(factoryMethod!=null && !"".equals(factoryMethod)){
			Class fclass = factoryBean==null||"".equals(factoryBean)?clazz:Class.forName(factoryBean);
			result = MethodUtils.invokeStaticMethod(fclass, factoryMethod, constructorArg);
		}else{
			result = ConstructorUtils.invokeConstructor(clazz, constructorArg);
		}
		setPropertys(result);
		initMethod(result);
		return result;
	}
	
	public void setPropertys(Object obj) throws IllegalAccessException, InvocationTargetException {
		if(obj==null){
			return ;
		}
		if(propertys!=null){
			BeanUtils.populate(obj, propertys);
		}
	}
	
	public void initMethod(Object obj) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException{
		if(obj ==null || initMethod==null || "".equals(initMethod)){
			return;
		}
		MethodUtils.invokeMethod(obj, initMethod, initArg);
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
		try {
			this.clazz = Class.forName(className);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e.getMessage() , e);
		}
	}
	public String getInitMethod() {
		return initMethod;
	}
	public void setInitMethod(String initMethod) {
		this.initMethod = initMethod;
	}
	public Map<String, Object> getPropertys() {
		return propertys;
	}
	public void setPropertys(Map<String, Object> propertys) {
		this.propertys = propertys;
	}
	public String getScope() {
		return scope;
	}
	public void setScope(String scope) {
		this.scope = scope;
	}

	public Object getSingle() {
		return single;
	}

	public void setSingle(Object single) {
		this.single = single;
	}

	public Object[] getInitArg() {
		return initArg;
	}

	public void setInitArg(Object[] initArg) {
		this.initArg = initArg;
	}

	public Object[] getConstructorArg() {
		return constructorArg;
	}

	public void setConstructorArg(Object[] constructorArg) {
		this.constructorArg = constructorArg;
	}

	public String getDescribe() {
		return describe;
	}

	public void setDescribe(String describe) {
		this.describe = describe;
	}
	

	public Class getClazz() {
		return clazz;
	}

	public void setClazz(Class clazz) {
		this.clazz = clazz;
	}
	

	public String getFactoryBean() {
		return factoryBean;
	}

	public void setFactoryBean(String factoryBean) {
		this.factoryBean = factoryBean;
	}

	public String getFactoryMethod() {
		return factoryMethod;
	}

	public void setFactoryMethod(String factoryMethod) {
		this.factoryMethod = factoryMethod;
	}

	@Override
	public String toString() {
		return "CBean [name=" + name + ", className=" + className + ", initMethod=" + initMethod + ", initArg="
				+ Arrays.toString(initArg) + ", scope=" + scope + ", propertys=" + propertys + ", constructorArg="
				+ Arrays.toString(constructorArg) + ", describe=" + describe + ", factoryBean=" + factoryBean
				+ ", factoryMethod=" + factoryMethod + ", single=" + single + ", clazz=" + clazz + "]";
	}
	
}
